import { EventHandler } from './handlers/event';
import { MenuManager } from './managers/menu';
import { SelectionManager } from './managers/selection';
import { ValueManager } from './managers/value';
import type { CascaderOptions } from './types/options';
import { randomStr } from './utils/common';
import { getNextLevelData } from './utils/data';
import { query, queryAll } from './utils/query';


export default class Cascader {
    private container: string;
    private uuid: string;
    private splitStr: string = "__CASCADER_SPLIT__";
    private menuManager: MenuManager;
    private selectionManager: SelectionManager;
    private valueManager: ValueManager;
    private eventHandler: EventHandler;
    private options: CascaderOptions;
    private valValue: any[] = [];



    constructor(container: string, options: CascaderOptions) {
        this.container = container;
        this.uuid = randomStr(6);
        this.options = options ?? {};
        this.menuManager = new MenuManager(this.uuid, this.splitStr, this.options);
        this.selectionManager = new SelectionManager(this.uuid, this.options);
        this.valueManager = new ValueManager(this.uuid, this.splitStr, this.options, this.valValue);
        this.eventHandler = new EventHandler(this.uuid, this.splitStr, this.options, this.menuManager, this.selectionManager, this.valueManager, this.valValue);
        const { data = [] } = this.options;

        if (!container) {
            console.error("container selector is required");
            return;
        }

        if (["document", "body"].indexOf(container) !== -1) {
            console.error(`The value of container cannot be '${container}'`);
            return;
        }

        if (!Array.isArray(data)) {
            console.error(`data must be array`);
            return;
        }
    }

    init() {
        const { mode = "single", data = [], defaultValue, showClear = true, placeholder = "" } = this.options;

        const container = query(this.container, this.uuid, true);

        if (!container) {
            console.error("can not find container");
            return;
        }

        const isMultiple = mode === "multiple" ? `cascader-container_multiple` : ``;

        const clearSvg = `<div class="cascader-container_clear">&times;</div>`;

        // 创建搜索框HTML（如果启用了搜索功能）
        const searchBoxHtml = this.options.showSearch ? `
            <div class="cascader-container_search">
                <input 
                    type="text" 
                    class="cascader-container_search_input" 
                    placeholder="${this.options.searchPlaceholder || '搜索'}" 
                    autocomplete="off"
                />
                <div class="cascader-container_search_clear" style="display: none;">&times;</div>
            </div>` : '';

        container.innerHTML = `
            <div class="cascader-container cascader-container_${this.uuid} ${isMultiple}">
                <div class="cascader-container_value"></div>
                <div class="cascader-container_edit_value" style="display: none;">${searchBoxHtml}</div>
                ${showClear ? clearSvg : ""}
                <div class="cascader-container_arrow">
                    <div class="cascader-container_arrow_icon">
                    </div>
                </div>
                <div class="cascader-container_menus"></div>
            </div>
        `;

        this.menuManager.createMenu(data);

        this.eventHandler.initEvents();

        this.setValue(defaultValue);
    }

    setValue(value: any[] = []) {
        if (!Array.isArray(value)) {
            console.error(`value must be array`);
            return;
        }

        const { data = [], mode = "single" } = this.options;

        if (mode === "multiple") {
            if (!value.every((ele) => Array.isArray(ele))) {
                console.error(
                    `value must be two-dimensional array in multiple mode. like this: [["sichuan", "chengdu", "jinli"], ["sichuan", "chengdu", "wuhouci"], ["hongkong"]]`,
                );
                return;
            }
        }

        const allMenu = queryAll(".cascader-container_menus_menu", this.uuid) ?? [];
        for (let index = 0; index < allMenu.length; index++) {
            const element = allMenu[index] as HTMLElement;
            query(".cascader-container_menus", this.uuid)?.removeChild(element);
        }
        this.menuManager.createMenu(data);

        const getValue = (value: string[]|number[]) => {
            let valueArr: (string|number)[] = [];

            if (value.every((item) => typeof item === "string") || value.every((item) => typeof item === "number")) {
                if (value.every((item) => typeof item === "number")) {
                    valueArr = [...this.valueManager.transformValue("getValue", value)];
                } else {
                    valueArr = [...value];
                }

                for (let index = 0; index < valueArr.length; index++) {
                    const levelValue = valueArr.slice(0, index + 1) as string[]|number[];
                    const tagStr = levelValue.join(this.splitStr);
                    const currentItem = query(`.cascader-container_menus_menu_item[data-tag="${tagStr}"]`, this.uuid);
                    const nextLevelData = getNextLevelData(levelValue, this.options);

                    if (nextLevelData.length !== 0) {
                        const menu = query(`.cascader-container_menus_menu[data-level="${index + 1}"]`, this.uuid);

                        if (menu) {
                            query(".cascader-container_menus", this.uuid)?.removeChild(menu);
                        }

                        this.menuManager.createMenu(nextLevelData, index + 1, tagStr);
                    }

                    if (mode !== "multiple") {
                        currentItem?.classList.add("cascader-container_menus_menu_item_active");
                    }
                }
            }

            return valueArr;
        };

        if (mode === "multiple") {
            const valueArr: (string|number)[][] = [];

            for (let index = 0; index < value.length; index++) {
                const element = value[index] as string[]|number[];
                valueArr.push(getValue(element));
            }

            this.valValue = [...valueArr];
        } else {
            this.valValue = [...getValue(value as string[]|number[])];
        }

        this.valueManager.renderValue(this.valValue);
    }

    get value() {
        return this.valValue;
    }

    get labelValue() {
        return this.valueManager.transformValue("getLabelValue", this.valValue);
    }

    get indexValue() {
        return this.valueManager.transformValue("getIndexValue", this.valValue);
    }
}

export type CascaderInstance = InstanceType<typeof Cascader>;